<?php
namespace Ayhome\Suite\Command;

use Swoole\Process;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\Container;
use think\facade\Config;
use think\facade\Env;
use think\swoole\Http as HttpServer;

/**
 * sutie HTTP 命令行，支持操作：start|stop|restart|reload
 * 支持应用配置目录下的swoole.php文件进行参数配置
 * 这玩意还玩不懂了？
 */
class Http extends Command
{
  protected $config = [];

  public function configure()
  {
    $this->setName('http')
      ->addArgument('action', Argument::OPTIONAL, "start|stop|restart|reload", 'start')
      ->addOption('host', 'H', Option::VALUE_OPTIONAL, 'the host of swoole server.', null)
      ->addOption('port', 'p', Option::VALUE_OPTIONAL, 'the port of swoole server.', null)
      ->addOption('daemon', 'd', Option::VALUE_NONE, 'Run the swoole server in daemon mode.')
      ->setDescription('suite HTTP Server for ThinkPHP');
  }

  public function execute(Input $input, Output $output)
  {
    $action = $input->getArgument('action');

    $this->init();

    if (in_array($action, ['start', 'stop', 'reload', 'restart'])) {
      $this->$action();
    } else {
      $output->writeln("<error>Invalid argument action:{$action}, Expected start|stop|restart|reload .</error>");
    }
  }

  protected function init()
  {
    $cfg = Config::pull('suite');
    $http_cfg = $cfg['http'];
    $mode = $http_cfg['mode'];
    $this->config = array_merge($http_cfg,$http_cfg[$mode]);
    unset($this->config['dev']);
    unset($this->config['defalut']);

    

    if (empty($this->config['pid_file'])) {
      $this->config['pid_file'] = Env::get('runtime_path') . 'suite:http.pid';
    }
    // 避免pid混乱
    $this->config['pid_file'] .= '_' . $this->getPort();

    if (empty($this->config['name'])) {
      $this->config['name'] = 'suite:http';
    }else{
      $this->config['name'] .= ':http';
    }
    // 避免pid混乱
    $this->config['name'] .= ':' . $this->getPort();

    // print_r($this->config);

    swoole_set_process_name($this->config['name']);
    
  }

  protected function getHost()
  {
    $host = !empty($this->config['host']) ? $this->config['host'] : '0.0.0.0';
    return $host;
  }

  protected function getPort()
  {
    $port = !empty($this->config['port']) ? $this->config['port'] : 9066;
    return $port;
  }

  /**
   * 启动server
   * @access protected
   * @return void
   */
  protected function start()
  {
    $pid = $this->getMasterPid();

    if ($this->isRunning($pid)) {
      $this->output->writeln('<error>sutie http server process is already running.</error>');
      return false;
    }

    $this->output->writeln('Starting sutie http server...');

    $host = $this->getHost();
    $port = $this->getPort();
    $mode = SWOOLE_PROCESS;
    $type = SWOOLE_SOCK_TCP;

    $ssl = !empty($this->config['ssl']) || !empty($this->config['open_http2_protocol']);
    if ($ssl) {
      $type = SWOOLE_SOCK_TCP | SWOOLE_SSL;
    }

    $swoole = new HttpServer($host, $port, $mode, $type);

    // 开启守护进程模式
    if ($this->input->hasOption('daemon')) {
      $this->config['daemonize'] = true;
    }
    // 设置应用目录
    $swoole->setAppPath($this->config['app_path']);

    // 创建内存表
    // if (!empty($this->config['table'])) {
    //   $swoole->table($this->config['table']);
    //   unset($this->config['table']);
    // }

    // $swoole->cachetable();

    // 设置文件监控 调试模式自动开启
    if (Env::get('app_debug') || !empty($this->config['file_monitor'])) {
      $interval = isset($this->config['file_monitor_interval']) ? $this->config['file_monitor_interval'] : 2;
      $paths    = isset($this->config['file_monitor_path']) ? $this->config['file_monitor_path'] : [];
      $swoole->setMonitor($interval, $paths);
      unset($this->config['file_monitor'], $this->config['file_monitor_interval'], $this->config['file_monitor_path']);
    }

    // 设置服务器参数
    if (isset($this->config['pid_file'])) {

    }
    $swoole->option($this->config);

    $this->output->writeln("sutie http server started: <http://{$host}:{$port}>");
    $this->output->writeln('You can exit with <info>`CTRL-C`</info>');

    $hook = Container::get('hook');
    $hook->listen("stuie_server_start", $swoole);

    $swoole->start();
  }

  /**
   * 柔性重启server
   * @access protected
   * @return void
   */
  protected function reload()
  {
    $pid = $this->getMasterPid();

    if (!$this->isRunning($pid)) {
      $this->output->writeln('<error>no sutie http server process running.</error>');
      return false;
    }

    $this->output->writeln('Reloading sutie http server...');
    Process::kill($pid, SIGUSR1);
    $this->output->writeln('> success');
  }

  /**
   * 停止server
   * @access protected
   * @return void
   */
  protected function stop()
  {
    $pid = $this->getMasterPid();

    if (!$this->isRunning($pid)) {
      $this->output->writeln('<error>no sutie http server process running.</error>');
      return false;
    }

    $this->output->writeln('Stopping sutie http server...');

    Process::kill($pid, SIGTERM);
    $this->removePid();

    $this->output->writeln('> success');
  }

  /**
   * 重启server
   * @access protected
   * @return void
   */
  protected function restart()
  {
    $pid = $this->getMasterPid();

    if ($this->isRunning($pid)) {
      $this->stop();
    }

    $this->start();
  }

  /**
   * 获取主进程PID
   * @access protected
   * @return int
   */
  protected function getMasterPid()
  {
    $pidFile = $this->config['pid_file'];

    if (is_file($pidFile)) {
      $masterPid = (int) file_get_contents($pidFile);
    } else {
      $masterPid = 0;
    }

    return $masterPid;
  }

  /**
   * 删除PID文件
   * @access protected
   * @return void
   */
  protected function removePid()
  {
    $masterPid = $this->config['pid_file'];

    if (is_file($masterPid)) {
      unlink($masterPid);
    }
  }

  /**
   * 判断PID是否在运行
   * @access protected
   * @param  int $pid
   * @return bool
   */
  protected function isRunning($pid)
  {
    if (empty($pid)) {
      return false;
    }

    return Process::kill($pid, 0);
  }
}
